import {Component, OnInit} from '@angular/core';
import {FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Validators} from '@angular/forms';
import {NzFormModule} from 'ng-zorro-antd/form';
import {NzInputDirective, NzInputGroupComponent} from "ng-zorro-antd/input";
import {NzIconDirective} from "ng-zorro-antd/icon";
import {NzButtonComponent} from "ng-zorro-antd/button";
import {NzImageModule} from "ng-zorro-antd/image";
import {AuthService} from "./auth.service";
import * as forge from 'node-forge';
import {HttpParams} from "@angular/common/http";
import {Router} from "@angular/router";
import {NzMessageService} from "ng-zorro-antd/message";
import {NzSpinComponent} from "ng-zorro-antd/spin";
import {Store} from "@ngrx/store";
import {AppState} from "../store";
import {getTokenSuccess} from "../store/auth/auth.action";

@Component({
    selector: 'app-login',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.less'],
    imports: [
        NzFormModule,
        FormsModule,
        ReactiveFormsModule,
        NzInputGroupComponent,
        NzIconDirective,
        NzInputDirective,
        NzButtonComponent,
        NzImageModule,
        NzSpinComponent
    ]
})
export class LoginComponent implements OnInit {
    passwordVisible: boolean = false;


    captchaKey: string = '';
    base64ImageCode: string = '';
    rsaPublicKey!: string;
    loginForm: FormGroup;

    isSpinning: boolean = false;

    /**
     * 构造函数
     * @param authService
     * @param fb
     * @param router
     * @param messageService
     * @param store
     */
    constructor(private authService: AuthService,
                private fb: FormBuilder,
                private router: Router,
                private messageService: NzMessageService,
                private store: Store<AppState>
    ) {

        // 构建响应式表单
        this.loginForm = this.fb.nonNullable.group({
            username: ['', [Validators.required]],
            password: ['', [Validators.required]],
            captcha: ['', [Validators.required]],
            remember: [true]
        });
    }


    ngOnInit(): void {
        this.refreshImgCode();
    }

    refreshImgCode() {
        this.authService.imgCode().subscribe(res => {
            this.base64ImageCode = res.base64ImageCode;
            this.rsaPublicKey = res.rsaPublicKey;
            this.captchaKey = res.captchaKey;
        });
    }

    /**
     * 执行RSA公钥加密
     */
    getEncryptPwd(password: any) {
        const pki = forge.pki;

        // 规定格式：publicKey之前需要加'-----BEGIN PUBLIC KEY-----\n'，之后需要加'\n-----END PUBLIC KEY-----'
        const publicKey = pki.publicKeyFromPem('-----BEGIN PUBLIC KEY-----\n' + this.rsaPublicKey + '\n-----END PUBLIC KEY-----');
        // forge通过公钥加密后一般会是乱码格式，可进行base64编码操作再进行传输，相应的，后台获取到密文的密码后需要先进行base64解码操作再进行解密
        const encode64Pwd = forge.util.encode64(publicKey.encrypt(password));
        return encodeURIComponent(encode64Pwd);
    }


    stringToUint8Array(str: any) {
        const arr = [];
        for (let i = 0, j = str.length; i < j; ++i) {
            arr.push(str.charCodeAt(i));
        }
        return new Uint8Array(arr);
    }

    /**
     * 登录
     */
    login(): void {
        const base64ClientInfo = 'Basic ' + forge.util.encode64('service-admin:123456');
        const param = new HttpParams()
            .set('grant_type', 'captcha') // 图形验证码模式（后台自定义授权模式）
            .set('username', this.loginForm.value.username)
            .set('password', this.getEncryptPwd(this.loginForm.value.password))
            .set('captcha', this.loginForm.value.captcha)
            .set('captchaKey', this.captchaKey);
        this.isSpinning = true;

        this.authService.login(param, base64ClientInfo).subscribe({
            next: (us) => {
                this.isSpinning = false;
                this.store.dispatch(getTokenSuccess({redirect: true}));
            },
            error: (err) => {
                this.messageService.create('error', err.error.errorTips);
                this.isSpinning = false;
                return;
            },
        });
    }
}
